module aworm
import StdEnv, japi

/* A slightly more complicated example, but not too much so.
   Choose the option <Start> from the <Game> menu, in order
   to begin playing. Use the arrow keys to drive the snake 
   towards food. The snake cannot go outside the premisses. 
   You win if the snake eats all five snacks.
*********************************************************** */

:: State = { x::!Framer, canvas::!Canvas, 
             key::!D, dialog::!Container, 
             run::!Entry, pause::!Entry,
             worm::![(!Int, !Int)], 
             dr::!(!Int, !Int),
             food::![(!Int, !Int)]}

dXdY s
  # kc= jkeycode s.key
  | kc == 37 = {s& dr=(-10, 0)}
  | kc == 39 = {s& dr=(10, 0)}
  | kc == 38 = {s& dr=(0, -10)}
  | kc == 40 = {s& dr=(0, 10)}
  | otherwise= s

gameover [(x,y):_]
   =  x<0 || x > 400 || y< 0 || y>400
gameover []= True

nofood []= True
nofood xs= False

game s js
 # (na, js)= jnextaction js
 | na== (act s.run)= run (jsetfocus s.canvas js) s 
 | otherwise= jquit js

run (cv, js) old 
  # new= mov old 
  # (cv, js)=  apply(wormDraw 8  old.worm) (color  white cv, js)
  # (cv, js)=  apply(wormDraw 6  new.worm) (color  blue cv, js)
  # (cv, js)= apply(food  old.food) (color white cv, js)
  # (cv, js)= apply(food  new.food) (color red cv, js) 
  # js= jsync js
  # (x,js) = jsleep 100 js 
  # (na,js) = jgetaction x js 
  | gameover new.worm= jquit (jdispose cv js) 
  | nofood new.food
      # (dlg, js)= jshow new.dialog js
      # js= jdispose cv js
      # (na, js)= jnextaction js
      = jquit js 
  | na== (act new.x) = jquit (jdispose cv js)
  | na== (act new.pause)
      # (na, js)= jnextaction js
      | na == (act new.run)= run(cv, js) new 
      | na == (act new.key)= run(cv, js) (dXdY new) 
      | otherwise= jquit (jdispose cv js)
  | na == (act new.key)= run (cv, js) (dXdY new) 
  | otherwise= run (cv, js) new 
                   
 
wormDraw r  [] cv = cv
wormDraw r  [p:xs] cv
   =  wormDraw r xs (jfill  (Cir p r) cv)

food  [] cv = cv
food  [p:xs] cv
   =  food  xs (jdraw  (Cir p 8) cv)

mov s
  # (neworm, newfood)= mv s.worm s.food s.dr
  = {s& worm= neworm, food= newfood}

mv  [(x,y):a] food (dx, dy)
 #  head= (x+dx, y+dy)
 = ([head:mbody [(x, y):a]], eat head food)
mv [] food d= ([(80,100), (70,100), 
          (60,100), (50,100), 
          (40, 100), (30, 100) ], food)

eat head []= []
eat (x, y) [(x1, y1):xs]
   # d= toReal((x-x1)*(x-x1) + (y-y1)*(y-y1))
   # distance= sqrt d
   | distance < 10.0 = eat (x, y) xs
   | otherwise = [(x1,y1):eat (x, y) xs]

mbody [] = []
mbody [x]= []
mbody [x:xs] = [x:mbody xs]

genfood w h js
 # (x, js)= jrandom (w-30) js
 # (y, js)= jrandom (h-30) js
 | x > 30 && x < w && y > 30 && y < h= ((x, y), js)
 | otherwise= genfood w h js
   
generateFood i xs w h js
   | i < 0 = (xs, js)
   # (f, js) = genfood w h js
   = generateFood (i-1) [f:xs] w h js
   
Start world
 # (js,world) = begin_japi world
   (fr, js) = jnewFrame  (XYWH 50 40 400 400) "Worm" js
   (cv, js) = jnewCanvas (XYWH 0 0 400 400) fr js
   (dlg, js) = jnewDialog (XY 30 60) "Congratulations" fr js
   (_, js)= jnewLabel (XY 10 50) "You win!" dlg js
   (dlg, js)= jpack dlg js
   (mnb, js) = jnewBar fr js
   (gamemn, js) = jnewMenu "Game" mnb js
   (start, js) = jnewItem  "Start" gamemn js 
   (ps, js) = jnewItem  "Pause" gamemn js
   (kp, cv) = jkeyboard cv
   (fr,js) = jshow fr js
   (foood, js)= generateFood 4 [] 400 400 js
   s= { x= fr, canvas= cv, key= kp, dialog=dlg, dr= (10, 0),
        run= start, pause= ps, worm=[],  food= foood}
   js = game s  js
 =   end_japi js world


